/**
 *
 * © Bahadir Zeren 2011
 * bzeren@gmail.com
 * No warranties, express or implied, are made for this program.
 *
 */

package org.baatar.net.client;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.baatar.net.message.IRequest;
import org.baatar.net.message.IResponse;

/**
 * Client connection class which is used to send messages to a TCP service.
 * 
 * @author b_zeren
 */
public class TCPClient {

    protected String callerInfo = null;
    private String hostName = null;
    private int portNo = 0;
    private int connectionTimeout = 0;

    /**
     * Sends a request message and waits for the response from TCP service.
     * 
     * @param request Request object to be sent.
     * 
     * @return IResponse object coming from TCP service after 
     * processing the request object.
     * 
     */
    public <T> IResponse<T> sendMessage(IRequest request, Class<T> type) throws Exception {
        return sendMessage(request, type, connectionTimeout);
    }

    /**
     * Sends a request message and waits for the response from TCP service.
     * 
     * @param request Request object to be sent.
     * 
     * @param connectionTimeout timeout value for the client socket.
     * 
     * @return IResponse object coming from TCP service after 
     * processing the request object.
     * 
     */
    public <T> IResponse<T> sendMessage(IRequest request, Class<T> type,
                                        int connectionTimeout) throws Exception {

        IResponse<T> res = null;

        Socket clientSocket = new Socket(hostName, portNo);
        clientSocket.setSoTimeout(connectionTimeout);
        try {
            OutputStream outputStream = clientSocket.getOutputStream();
            InputStream inputStream = clientSocket.getInputStream();
            ObjectOutputStream objOutputStream = new ObjectOutputStream(outputStream);
            ObjectInputStream objInputStream = null;

            try {
                objOutputStream.writeObject(request);
                objOutputStream.flush();
                objInputStream = new ObjectInputStream(inputStream);
                res = (IResponse) objInputStream.readObject();
            } finally {
                if (objOutputStream != null) {
                    objOutputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                if (objInputStream != null) {
                    objInputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            }
        } finally {
            clientSocket.close();
            clientSocket = null;
        }
        if (res.getException() != null) {
            throw res.getException();
        }

        return res;
    }

    /**
     * @return the connectionTimeout
     */
    public int getConnectionTimeout() {
        return connectionTimeout;
    }

    /**
     * @return connectionTimeout the connectionTimeout to set
     */
    public void setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    /**
     * @return the clientInfo
     */
    public String getCallerInfo() {
        return callerInfo;
    }

    /**
     * @param clientInfo the clientInfo to set
     */
    public void setCallerInfo(String callerInfo) {
        this.callerInfo = callerInfo;
    }

    /**
     * @return the hostName
     */
    public String getHostName() {
        return hostName;
    }

    /**
     * @param hostName the hostName to set
     */
    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    /**
     * @return the portNo
     */
    public int getPortNo() {
        return portNo;
    }

    /**
     * @param portNo the portNo to set
     */
    public void setPortNo(int portNo) {
        this.portNo = portNo;
    }

}
